package com.jiawa.train.business.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jiawa.train.business.domain.DailyTrainTicket;
import com.jiawa.train.business.dto.StockDeductDTO;
import com.jiawa.train.business.mapper.DailyTrainTicketMapper;
import com.jiawa.train.business.req.ConfirmOrderTicketReq;
import com.jiawa.train.common.context.LoginMemberContext;
import com.jiawa.train.common.exception.BusinessException;
import com.jiawa.train.common.resp.PageResp;
import com.jiawa.train.common.util.SnowUtil;
import com.jiawa.train.business.domain.ConfirmOrder;
import com.jiawa.train.business.domain.ConfirmOrderExample;
import com.jiawa.train.business.mapper.ConfirmOrderMapper;
import com.jiawa.train.business.req.ConfirmOrderQueryReq;
import com.jiawa.train.business.req.ConfirmOrderDoReq;
import com.jiawa.train.business.resp.ConfirmOrderQueryResp;
import jakarta.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.jiawa.train.common.exception.BusinessExceptionEnum.*;


@Service
public class ConfirmOrderService {

    private static final Logger LOG = LoggerFactory.getLogger(ConfirmOrderService.class);

    @Resource
    private ConfirmOrderMapper confirmOrderMapper;
    @Resource
    private DailyTrainTicketMapper dailyTrainTicketMapper;
    @Resource
    private StringRedisTemplate stringredisTemplate;

    @Resource
    private DailyTrainSeatService dailyTrainSeatService; // 之后选座会用到
    @Autowired
    private StreamBridge streamBridge;

    public void save(ConfirmOrderDoReq req) {
        DateTime now = DateTime.now();
        ConfirmOrder confirmOrder = BeanUtil.copyProperties(req, ConfirmOrder.class);
        if (ObjectUtil.isNull(confirmOrder.getId())) {
            confirmOrder.setId(SnowUtil.getSnowflakeNextId());
            confirmOrder.setCreateTime(now);
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.insert(confirmOrder);
        } else {
            confirmOrder.setUpdateTime(now);
            confirmOrderMapper.updateByPrimaryKey(confirmOrder);
        }
    }

    public PageResp<ConfirmOrderQueryResp> queryList(ConfirmOrderQueryReq req) {
        ConfirmOrderExample confirmOrderExample = new ConfirmOrderExample();
        confirmOrderExample.setOrderByClause("id desc");
        ConfirmOrderExample.Criteria criteria = confirmOrderExample.createCriteria();

        LOG.info("查询页码：{}", req.getPage());
        LOG.info("每页条数：{}", req.getSize());
        PageHelper.startPage(req.getPage(), req.getSize());
        List<ConfirmOrder> confirmOrderList = confirmOrderMapper.selectByExample(confirmOrderExample);

        PageInfo<ConfirmOrder> pageInfo = new PageInfo<>(confirmOrderList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());

        List<ConfirmOrderQueryResp> list = BeanUtil.copyToList(confirmOrderList, ConfirmOrderQueryResp.class);

        PageResp<ConfirmOrderQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(list);
        return pageResp;
    }

    public void delete(Long id) {
        confirmOrderMapper.deleteByPrimaryKey(id);
    }

    @Transactional
    public void doConfirm(ConfirmOrderDoReq req) {
        // 1. 校验业务参数（略）

        //方案二：Redis + MQ + Redisson锁
            //2.从Redis扣减库存
        List<ConfirmOrderTicketReq> tickets= req.getTickets();
        //按座位类型聚合需要购买的票数
        Map<String, Integer> seatCountMap=tickets.stream()
                .collect(Collectors.groupingBy(
                        ConfirmOrderTicketReq :: getSeatTypeCode,
                        Collectors.summingInt(t ->1)
                ));

        String redisKey= "ticket_inventory:" + req.getDailyTrainTicketId();
        //遍历每一种需要购买的座位票
        for (Map.Entry<String,Integer> entry : seatCountMap.entrySet()) {
            String seatTypeCode = entry.getKey();
            Integer count = entry.getValue();

        //2.1检查Redis库存
        Object stockObj=stringredisTemplate.opsForHash().get(redisKey, seatTypeCode);
        if (stockObj==null || Integer.parseInt((String) stockObj)<count){
            throw new BusinessException(BUSINESS_SYSTEM_BUSY_STOCK);
        }
        //2.2原子性扣减redis库存
            Long remainingStock=stringredisTemplate.opsForHash().increment(redisKey,seatTypeCode,-count.longValue());
            if (remainingStock<0) {
                //库存不足，回滚已扣减的库存
                stringredisTemplate.opsForHash().increment(redisKey,seatTypeCode,count.longValue());
                throw new BusinessException(BUSINESS_SYSTEM_BUSY);
            }
        }
        //3.选座逻辑
        //4.生成订单
        DateTime now = DateTime.now();
        ConfirmOrder confirmOrder = BeanUtil.copyProperties(req, ConfirmOrder.class);
        confirmOrder.setMemberId(LoginMemberContext.getId());
        confirmOrder.setId(SnowUtil.getSnowflakeNextId());
        confirmOrder.setCreateTime(now);
        confirmOrder.setUpdateTime(now);
        confirmOrder.setStatus("P");
        confirmOrder.setTickets(JSON.toJSONString(req.getTickets()));
        confirmOrderMapper.insert(confirmOrder);
        //5.发送 MQ消息，通知异步扣减数据库库存
        for (Map.Entry<String,Integer> entry : seatCountMap.entrySet()) {
            StockDeductDTO stockDeductDTO = new StockDeductDTO();
            stockDeductDTO.setDailyTrainTicketId(req.getDailyTrainTicketId());
            stockDeductDTO.setSeatTypeCode(entry.getKey());
            stockDeductDTO.setCount(entry.getValue());

            // Spring 事务提交后，再发送消息
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    try {
                        streamBridge.send("stockDeduct-out-0", stockDeductDTO);
                    } catch (Exception e) {
                        LOG.error("发送MQ消息失败 (after-commit)，订单ID：{}，错误信息：{}", confirmOrder.getId(), e.getMessage());
                        // 这里可以根据业务需求，记录失败的MQ消息，后续进行补偿
                    }
                }
            });
        }
        LOG.info("购票核心流程处理完毕，订单ID：{}", confirmOrder.getId());
        //方案一：MySQL + Redisson锁
        // 2. 查出余票记录
//        DailyTrainTicket ticket = dailyTrainTicketMapper.selectByPrimaryKey(req.getDailyTrainTicketId());
//        if (ticket == null) {
//            throw new BusinessException(BUSINESS_SYSTEM_BUSY);
//        }
//
//        // 3. 判断余票是否充足（这里只以一等座为例，实际应遍历req.getTickets()按类型分别判断）
//        int needCount = req.getTickets().size();
//        if (ticket.getYdz() < needCount) {
//            throw new BusinessException(BUSINESS_SYSTEM_BUSY);
//        }
//
//        // 4. 扣减余票（乐观锁，防止并发超卖）
//        DailyTrainTicket updateTicket = new DailyTrainTicket();
//        updateTicket.setId(ticket.getId());
//        updateTicket.setYdz(ticket.getYdz() - needCount);
//        int updateCount = dailyTrainTicketMapper.updateByPrimaryKeySelective(updateTicket);
//        if (updateCount == 0) {
//            throw new BusinessException(BUSINESS_SYSTEM_BUSY);
//        }
//
//        // 5. 选座逻辑（简化版，实际应遍历所有车厢、座位，找到可用的座位，更新sell字段）
//        // 这里只做伪代码，实际要结合sell字段的区间位运算
//        for (ConfirmOrderTicketReq ticketReq : req.getTickets()) {
//            // 选座算法：查找可用座位，更新sell字段为已售
//            // 1. 查询所有可用座位
//            // 2. 判断sell字段区间是否可卖
//            // 3. 更新sell字段
//            // 4. 记录选中的座位信息
//        }
//
//        // 6. 生成订单
//        ConfirmOrder order = new ConfirmOrder();
//        order.setId(SnowUtil.getSnowflakeNextId());
//        order.setMemberId(req.getMemberId());
//        order.setDate(req.getDate());
//        order.setTrainCode(req.getTrainCode());
//        order.setStart(req.getStart());
//        order.setEnd(req.getEnd());
//        order.setDailyTrainTicketId(req.getDailyTrainTicketId());
//        order.setTickets(JSON.toJSONString(req.getTickets())); // 记录购票明细
//        order.setStatus("S"); // 成功
//        order.setCreateTime(new Date());
//        order.setUpdateTime(new Date());
//        confirmOrderMapper.insert(order);

        // 7. 其他后续处理（如通知、积分等，可选）
    }
}
